import { onMounted, onUnmounted } from "vue"
import { events } from "./events"
import { cloneDeep } from 'lodash'

export function useCommonState(data, focusData) {
    const state = { // 前进和后退需要指针
        current: -1, // 前进和后退的索引值
        queue: [], // 存放所有的操作命令
        stackCommands: {}, // 命令和执行的映射表
        registerList: [], // 保存所有的指令
        destroyList: [],  // 销毁的指令
    }

    // 注册命令的方法
    const register = (commonObj) => {
        state.registerList.push(commonObj)
        // 接收参数
        state.stackCommands[commonObj.name] = (...args) => {
            const { redo, undo } = commonObj.execute(...args)
            redo()
            if (!commonObj.pushQueue) return
            // 组件1-组件2-撤销-组件3
            // 组件1-组件3
            // 如果在拖拽的过程中有撤销行为，
            let { queue, current } = state
            if (queue.length > 0) {
                queue = queue.slice(0, current + 1)
                state.queue = queue
            }
            // 把指令放到队列中,根据标识放入队列
            state.queue.push({ redo, undo })
            state.current = current + 1
        }
    }

    // 注册一个撤销的命令
    register({
        name: 'undo',
        keyBord: 'ctrl+z',
        execute() {
            return {
                redo() {
                    if (state.current == -1) return
                    let item = state.queue[state.current]
                    if (item) {
                        item.undo()
                        state.current--
                    }
                }
            }
        }
    })

    // 注册一个还原的命令
    register({
        name: 'redo',
        keyBord: 'ctrl+y',
        execute() {
            return {
                redo() {
                    let item = state.queue[state.current + 1]
                    if (item) {
                        item.redo()
                        state.current++
                    }
                }
            }
        }
    })

    register({
        name: 'drag',
        pushQueue: true, // 如果希望将操作放到队列中增加一个标识
        init() { // 初始化操作，默认会执行
            this.before = null
            // 拖拽执之前记录状态
            const start = () => {
                this.before = cloneDeep(data.value.blocks)
            }
            // 拖拽执行之后要出发drag事件
            const end = () => {
                state.stackCommands.drag()
            }
            // 监听开始和结束事件
            events.on('start', start)
            events.on('end', end)
            // 执行完销毁
            return () => {
                events.off('start', start)
                events.off('end', end)
            }
        },
        execute() {
            let before = this.before // 之前的状态
            let after = data.value.blocks // 之后的状态
            return {
                redo() {
                    data.value = { ...data.value, blocks: after }
                },
                undo() {
                    data.value = { ...data.value, blocks: before }
                }
            }
        }
    });

    // 记录导入导出的状态
    register({
        name: 'updateContainer',
        pushQueue: true, // 记录标识，没有的话，不会记录状态在对列表中
        execute(newValue) {
            // 保存之前和之后的数据
            const state = {
                before: data.value,
                after: newValue
            }
            return {
                redo() {
                    data.value = state.after
                },
                undo() {
                    data.value = state.before
                }
            }
        }
    })

    // 置顶
    register({
        name: 'placeTop',
        pushQueue: true, // 记录标识，没有的话，不会记录状态在对列表中
        execute() {
            // 保存之前和之后的数据
            const state = {
                before: cloneDeep(data.value.blocks),
                after: (() => {
                    // 求出没有被选中的最大的zIndex,
                    let maxzIndex = focusData.value.unFocused.reduce((pre, block) => {
                        return Math.max(pre, block.zIndex)
                    }, -Infinity)

                    // 改变被选中的zIndex, 选择最大的这个元素，让zindex + 1
                    focusData.value.focused.forEach((block) => {
                        block.zIndex = maxzIndex + 1
                    })
                    return data.value.blocks
                })()
            }
            return {
                redo() {
                    data.value = { ...data.value, blocks: state.after }
                },
                undo() {
                    data.value = { ...data.value, blocks: state.before }
                }
            }
        }
    })

    // 置底
    register({
        name: 'placeBottom',
        pushQueue: true, // 记录标识，没有的话，不会记录状态在对列表中
        execute() {
            // 保存之前和之后的数据
            const state = {
                before: cloneDeep(data.value.blocks),
                after: (() => {
                    // 被选中的数据zidex相减的话会有负值
                    // 没有被选中的
                    // 求出最小的zindex
                    // 求出没有被选中的最大的zIndex,
                    let minzIndex = focusData.value.unFocused.reduce((pre, block) => {
                        return Math.min(pre, block.zIndex)
                    }, 0)
                    // 如果小于0，把最小zindex 置为0
                    if (minzIndex < 0) {
                        minzIndex = 0
                        const dur = Math.abs(minzIndex)
                        // 把没有被选中的zindex往上加
                        focusData.value.unFocused.forEach((block) => block.zIndex += dur)
                    }
                    // 被选中的直接为最小值
                    focusData.value.focused.forEach((block) => block.zIndex = minzIndex)
                    return data.value.blocks;
                })()
            }
            return {
                redo() {
                    data.value = { ...data.value, blocks: state.after }
                },
                undo() {
                    data.value = { ...data.value, blocks: state.before }
                }
            }
        }
    })

    // 删除数据
    register({
        name: 'delete',
        pushQueue: true,
        keyBord: 'delete',
        execute() {
            let state = {
                before: data.value.blocks,
                after: focusData.value.unFocused
            }
            return {
                redo() {
                    data.value = { ...data.value, blocks: state.after }
                },
                undo() {
                    data.value = { ...data.value, blocks: state.before }
                }
            }
        }
    })

    // 更新一条数据
    register({
        name: 'updateBlock',
        pushQueue: true,
        execute(newBlock, oldBlock) {
            let state = {
                before: data.value.blocks,
                after: (() => {
                    // copy一份数据
                    let blocks = [...data.value.blocks]
                    // 查找旧数据的index并替换
                    const index = data.value.blocks.indexOf(oldBlock)
                    if (index !== -1) {
                        blocks.splice(index, 1, newBlock)
                    }
                    return blocks
                })()
            }
            return {
                redo() {
                    data.value = { ...data.value, blocks: state.after }
                },
                undo() {
                    data.value = { ...data.value, blocks: state.before }
                }
            }
        }
    })



    // 键盘事件
    const keybaordEvent = (() => {
        // 设置keycode 对象
        const keyCodes = {
            90: 'z',
            89: 'y',
            46: 'delete'
        }
        const onKeydown = (e) => {
            const { ctrlKey, keyCode } = e
            // 是否按住可ctrl键
            let stringKey = [] // 存储ctrl+z ctrl+y

            // 判断是否按了ctrl键
            if (ctrlKey) stringKey.push('ctrl');

            // 如果没有按住z 或者 y 键，return
            if (keyCodes[keyCode]) stringKey.push(keyCodes[keyCode])

            // 把数组转化成ctrl+z的字符串
            if (stringKey.length > 1) stringKey = stringKey.join('+')

            // 只按一个键时把数组用空字符转成字符串
            if (stringKey.length === 1) stringKey = stringKey.join('')

            state.registerList.forEach(({ keyBord, name }) => {
                if (!keyBord) return;
                if (stringKey === keyBord) {
                    state.stackCommands[name]()
                    e.preventDefault();
                }
            })
        }

        // 初始化数据
        const init = () => {
            // 添加键盘事件
            window.addEventListener('keydown', onKeydown)
            return () => {
                // 页面卸载，销毁事件
                window.removeEventListener('keydown', onKeydown)
            }
        }

        return init
    })();

    (() => {
        state.destroyList.push(keybaordEvent())
        // 循环所有的指令，如果有初始化的方法就执行, 并把要销毁的内容保存到销毁的数组中
        state.registerList.forEach((item) => item.init && state.destroyList.push(item.init()))
    })();

    onUnmounted(() => {
        state.destroyList.forEach((fn) => fn && fn())
    })

    return state
}